package cn.com.HiSting1990.MyBasis;

import java.util.Date;
import java.util.concurrent.*;

public class myThreadPool {
    public static void main(String[] args) {

        myExecutors();
    }

    private static void myThreadPools(){
        
    }

    private static void myExecutors(){
//        myFixedThreadPoolsOne();
//        myFixedThreadPoolsSecond();
//        myCachedThreadPool();
//        mySingleThreadExecutor();
//        myScheduledThreadPool();
//        mySingleThreadScheduledExecutor();
//        myNewWorkStealingPool();
        myThreadPoolExecutor();
    }

    //创建固定线程数的线程池（第一种）(FixedThreadPoolsSecond),优先这种（我现在的想法）
    //创建一个固定大小的线程池，可控制并发的线程数，超出的线程会在队列中等待
    private static void myFixedThreadPoolsOne(){
        //创建2个数据级的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        //创建任务，业务代码
        Runnable runnable = new Runnable(){

            @Override
            public void run() {
                System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
            }
        };

        //线程池执行任务（一次添加4个任务）
        //执行任务的方法有两种：submit 和 execute
        threadPool.submit(runnable);

        //执行方式2：execute
        threadPool.execute(runnable);
        threadPool.execute(runnable);
        threadPool.execute(runnable);
    }
    //创建固定线程数的线程池（第二种）(FixedThreadPoolsSecond)
    //创建一个固定大小的线程池，可控制并发的线程数，超出的线程会在队列中等待
    private static void myFixedThreadPoolsSecond(){
        //创建2个数据级的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        //创建任务，业务代码
        threadPool.execute(() ->{
            System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
        });
        threadPool.execute(() ->{
            System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
        });
        threadPool.execute(() ->{
            System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
        });
        threadPool.execute(() ->{
            System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
        });
    }
    //创建缓存的线程的线程池(CachedThreadPool)
    //创建一个可缓存的线程池，若线程数超过处理所需，缓存一段时间后会回收，若线程数不够，则新建线程
    private static void myCachedThreadPool(){
        //创建线程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        //创建任务，业务代码
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
            }
        };

        //使用execut方法执行
        for (int i=0;i<10;i++){
            threadPool.execute(runnable);
//            try {
//                TimeUnit.SECONDS.sleep(1);
//            }catch (InterruptedException e){
//                System.out.println(e);
//            }
        }
        //使用submit方法执行
//        for (int i=0;i<10;i++){
//            threadPool.submit(runnable);
//        }
    }
    //创建单个线程数的线程池，它可以保证先进先出的执行顺序(ingleThreadExecutor)
    private static void mySingleThreadExecutor(){
        //创建单线程的线程池
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
        //创建任务，业务代码
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
            }
        };

        //线程池执行任务(执行10次)
        for (int i=0;i<10;i++){
            threadExecutor.execute(runnable);
        }
    }

    //创建一个可以执行延迟任务的线程池(ScheduledThreadPool)
    private static void myScheduledThreadPool(){
        //创建线程池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
        //创建任务，业务代码
        Runnable runnable = () -> {
            System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
            System.out.println(new Date());
        };
        //线程池执行业务代码
        System.out.println(new Date());
        threadPool.schedule(runnable,5,TimeUnit.SECONDS);
    }

    //创建一个单线程的可以执行延迟任务的线程池（SingleThreadScheduledExecutor）
    private static void mySingleThreadScheduledExecutor(){
        //创建线程池
        ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
        //业务代码
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("任务被线程 "+Thread.currentThread().getName()+" 执行");
                System.out.println(new Date());
            }
        };
        System.out.println(new Date());
        //线程池执行业务代码
        singleThreadScheduledExecutor.schedule(runnable,5,TimeUnit.SECONDS);
    }
    //创建一个抢占式执行的线程池（任务执行顺序不确定），注意此方法只有在 JDK 1.8+ 版本中才能使用（newWorkStealingPool）
    private static void myNewWorkStealingPool(){
        //创建线程池
        ExecutorService newWorkStealingPool = Executors.newWorkStealingPool();
        //线程池执行业务代码
        for (int i=0;i<10;i++){
            final int index = i;
            newWorkStealingPool.execute(() ->{
                System.out.println(index+"任务被线程 "+Thread.currentThread().getName()+" 执行");
            });
        }
        while (!newWorkStealingPool.isTerminated()){}
    }

    //最原始的创建线程池的方式，它包含了 7 个参数可供设置（ThreadPoolExecutor）,这个我觉得和第一个一样有用，这个比第一个更加适应环境
    //阿里的《java开发手册》：
        //【强制】线程池不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。
        //说明：Executors 返回的线程池对象的弊端如下：
            //1）FixedThreadPool 和 SingleThreadPool：允许的请求队列长度为 Integer.MAX_VALUE，可能会堆积大量的请求，从而导致 OOM。
            //2）CachedThreadPool：允许的创建线程数量为 Integer.MAX_VALUE，可能会创建大量的线程，从而导致 OOM。
    //这个是七个中唯一使用Thread创建的
    private static void myThreadPoolExecutor(){
        //创建线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,100,TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10));
        //线程池执行业务代码
        for (int i=0;i<10;i++){
            final int index = i;
            threadPoolExecutor.execute(()->{
                System.out.println(index+"任务被线程 "+Thread.currentThread().getName()+" 执行");
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            });
        }
    }
}
